<?php
require_once( '__config__.php' );
require_once( 'Base.php' );

/**
 * Provides a wrapper used by page scripts to generate HTML, interact
 * with the database, and so forth.
 */
class Backend extends Base {
    #################################################
    ## Properties
    #################################################    
    /**
     * @var string The current page's filename, like "index.php".
     */
    private $filename  = NULL;
    
    /**
     * @var string The page title, usually the name of the script.
     */
    private $title     = NULL;
    private $blurb     = NULL; // a short description displayed at the top of the page; defaults to nothing.
    private $path      = NULL; // path breadcrumbs (defaults to title)
    private $source    = NULL; // array of files to display source for
    private $license   = NULL; // script license text (defaults to text in __config__.php)
    private $hook_head = NULL; // extra content to insert into HTML <head>
    private $modules_path = '../backend/modules/';
    
    private $valid_construct_opts = Array( 'title', 'blurb', 'path', 'source', 'license', 'modules_path' );

    #################################################
    ## Constructor
    ## Build backend, given any of the following data in a hash (see properties):
    ##    - title
    ##    - blurb
    ##    - path
    ##    - source
    ##    - license
    ##    - modules_path
    #################################################
    public function __construct( $options ) {
        parent::__construct();
        
        /* validate options */
        $invalid = array_diff( array_keys($options), $this->valid_construct_opts );
        if( $invalid )
            die( "Invalid keys given to Backend constructor: '" . join("' and '", array_keys($invalid)) . "'." );
        
        /* get configuration */
        global $gconfig;
        $this->config = &$gconfig;
        
        /* handle options */
        $this->filename = basename( $_SERVER['SCRIPT_NAME'] );
        $this->title    = isset($options['title']) ? $options['title']   : $this->filename;
        $this->blurb    = isset($options['blurb']) ? $options['blurb']   : NULL;
        $this->path     = isset($options['path']) ? $options['path']     : array(&$this->title);
        $this->license  = isset($options['license']) ? $options['license'] : $gconfig['license'];
        $this->source   = isset($options['source']) ? $options['source'] : NULL;
        $this->modules_path = isset($options['modules_path']) ? $options['modules_path'] : $this->modules_path;
        $this->scripts = NULL;
    }


    #################################################
    ## HTTP encapsulation
    #################################################
    #############################
    ## Return absolute URL given path relative to public_html
    #############################
    public function url( $path ) {
        return $this->config['root_url'] . $path;
    }


    #############################
    ## Link to external files in the header
    #############################
    public function link( $files ) {
        if( !is_array($files) )
            $files = array( $files );
        $this->source = array_merge( $this->source, $files );

        foreach( $files as $file ) {
            $ext = substr( $file, -3 );
            switch( $ext ) {
                case 'css':
                    $this->hook_head .= "<link rel='stylesheet' type='text/css' href='{$file}' />";
                    break;
                case '.js':
                    $this->hook_head .= "<script type='text/javascript' src='{$file}'></script>";
                    break;
                default:
                    die( "Invalid extension '{$ext}' (file '{$file}') passed to Backend::link." );
            }
        }
    }
    
    public function addScript( $script ) {
        $this->hook_head .= "<script type=\"text/javascript\">\n{$script}\n</script>";
    }


    #############################
    ## Print header
    #############################
    public function header() {
        /* print document head */
        echo "
<!-- begin generated header -->
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.1//EN' 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en'>
    <head>
        <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
        <title>{$this->title}</title>
        <link rel='shortcut icon' href='{$this->config['style_url']}favicon.ico' />

        {$this->hook_head}
    </head>
    <body>
\n";
        
        /* print content head */
        echo "
         <div id='content-column'>
            <div id='content'>
                <h1>{$this->title}</h1>
                <p>{$this->blurb}</p>
<!-- end generated header -->\n";
        
        /* print source */
        if( isset($_REQUEST['action']) && $_REQUEST['action'] == 'source' )
             $this->showSource();
    }
    
    #############################
    ## Print footer
    #############################
    public function footer() {
        /* generate benchmarks */
        $precisionPercentage = $this->config['profile_perc_precision'];
        $precisionTime = $this->config['profile_time_precision'];
        $totalTime = $this->TimerGetElapsedSinceStart();
        $timerResults = array();
        foreach( $this->TimerGetKeys() as $key )
        {
            $time = $this->TimerGetElapsed($key);
            $this->_footer_benchmarks[$key] = sprintf(
                "%s (%s%%)",
                round($time, $precisionTime),
                round($time / $totalTime * 100, $precisionPercentage)
            );
        }
//        
        /* output */
        echo "
<!-- begin generated footer -->
</div>
            <div id='sidebar'>
<ul>
<li>
<h2>License</h2>
          <small>Code adapted from <a href='http://toolserver.org/~pathoschild/accounteligibility/'>Pathoschild's accounteleligibility tool.</a> Design by <a href='http://www.freecsstemplates.org/'>Free CSS Templates</a>. {$this->license} Please report bugs or request features at <a href='http://code.google.com/p/monotools/issues/entry'>this page</a>.</small><br /><br />
                Page generated in " . round( $totalTime, $precisionTime ) . " seconds.<br /><br />
                <a href='http://validator.w3.org/check?uri=referer'><img
                src='http://www.w3.org/Icons/valid-xhtml11'
                alt='Valid XHTML 1.1' height='31' width='88' /></a><a rel='license' href='http://creativecommons.org/licenses/by-sa/3.0/'><img alt='Creative Commons License' style='border-width:0' src='http://i.creativecommons.org/l/by-sa/3.0/88x31.png' /></a>
            <a href='http://jigsaw.w3.org/css-validator/check/referer'>
    <img style='border:0;width:88px;height:31px'
        src='http://jigsaw.w3.org/css-validator/images/vcss-blue'
        alt='Valid CSS!' /></a><a href='http://toolserver.org'><img src='http://toolserver.org/~soxred93/pjirc/wikimedia-toolserver-button.png' width='88' height='31' alt='Wikimedia Toolserver banner' /></a></li>
        <li>
<h2>Voting</h2>
          <big>Once you check your status, you may view the Round 1 gallery at <a href='http://commons.wikimedia.org/wiki/Commons:Picture_of_the_Year/2010/Galleries'>this page</a>.</big></li>
</ul></div>
      ";
        
        if(count($timerResults)) {
            echo "<br />
                Benchmarks:<br />
            ";
            foreach( $timerResults as $name => $time ) {
                echo "
                    &emsp;&emsp;{$name}: {$time}<br />";
            }
            echo "
                </table>";
        }
        
        echo "

        </div>
    </body>
</html>";
    }

    #############################
    ## Print source code
    #############################
    public function showSource() {
        /* print source header */
        echo "
                <!-- generated source code -->
                <h2>Source code (<a href='{$this->filename}' title='hide source code'>hide</a>)</h2>
                <div id='source' class='section'>\n";
        
        /* warn about closed-source scripts */
        if( !$this->source ) {
            echo "
                <div class='error'>No files are marked as open-source for this script. This is probably because they are still in development, or due to an oversight.</div>\n";
        }
        
    
        /* fetch list of modules */
        $modules = Array();
        $path = $this->modules_path;
        $dir = dir( $path ) or print "
                <div class='error'>Can't read module directory ({$path}).</div>\n";
        if( $dir ) {
            while( $file = $dir->read() ) {
                if( preg_match('/\.php$/', $file) )
                    $modules[] = "$path$file";
            }
        }
        
        /* print table of contents */
        echo "
                    <div id='toc'>
                        <b>Table of contents</b>
                        <ul>\n";                        
        if( $this->source )
            $this->_source_toc( 'Script', $this->source );
        $this->_source_toc( 'Generic modules', $modules );
        echo "
                        </ul>
                    </div>\n";
        
        /* print source files */
        if( $this->source )
            $this->_source_files( 'Script', $this->source );
        $this->_source_files( 'Generic modules', $modules );
        echo "
        </div>\n";

    }

    #################################################
    ## Private methods
    #################################################
    #############################
    ## Print source code TOC entries
    #############################
    private function _source_toc( $name, $items ) {
        echo "
                        <li>{$name}
                            <ol>\n";
                            
        foreach( $items as $file ) {
            $anchor = $this->strip_nonlatin( $file );
            echo "
                                <li><a href='#{$anchor}' title='section for {$file}'>{$file}</a></li>\n";
        }
        echo "
                            </ol>
                        </li>\n";
    }


    #############################
    ## Print source code files
    #############################
    private function _source_files( $name, $items ) {
        foreach( $items as $file ) {
            $anchor = $this->strip_nonlatin($file);
            echo "
                    <h3 id='{$anchor}'>{$file}</h3>
                    <a href='#toc' title='toc'>back to toc</a>
                    <div class='source'>";
            highlight_file($file);
            echo "
                    </div>\n";
        }
    }
}
?>
